/**
 * tigerrad
 * fall 2006
 */

#ifndef _PROGRAM_H
#define _PROGRAM_H

#include "Util.h"
#include "Shader.h"

class Program;
typedef boost::shared_ptr<Program> ProgramPtr;

/**
 *  GLSL Program, composed of a vertex shader and a fragment shader.
 */
class Program
{
	public:

		/**
		 * Constructor. Will generate the Program name.
		 * @param name Debug name
		 * @param v Vertex shader, can be null.
		 * @param f Fragment shader, can be null.
		 */
		Program(const std::string& name, ShaderPtr v, ShaderPtr f);

		/**
		 * Constructor.  Will load the shaders.
		 * @param name Debug name
		 * @param vPath Path to vertex shader.
		 * @param fPath Path to fragment shader.
		 */
		Program(const std::string& n, const std::string& vPath, const std::string& fPath);

		/**
		 * Return the debug name.
		 */
		std::string getName() const { return _name; }

		/**
		 * Return the OpenGL name (reference)
		 */
		GLuint getGLName() const { return _glName; }

		/**
		 * Return the vertex shader
		 */
		ShaderPtr getVert() const { return _vert; }

		/**
		 * Return the fragment shader
		 */
		ShaderPtr getFrag() const { return _frag; }
		
		/**
		 * Set the uniform float value
		 */
		void setFloat(const std::string& name, GLfloat s);

		/**
		 * Set the uniform int value
		 */
		void setInt(const std::string& name, GLint s);

		/**
		 * Set the Sampler value
		 */
		void setSampler(const std::string& name, GLuint s);

		/**
		 * Set a 4x4 Matrix.
		 */
		void setMatrix(const std::string& name, const Matrix& mat);

		/**
		 * Set a Vec2
		 */
		void setVec2(const std::string& name, const Vec2f& v);

		/**
		 * Set a Vec2 array
		 */
		void setVec2Array(const std::string& name, GLuint num, Vec2f* c);
		
		/**
		 * glUseProgram.
		 * TODO avoid reloading 
		 */
		void load() const { glUseProgram(_glName); }

		/**
		 * Unload the program. glUseProgram(0)
		 * TODO error if program not loaded
		 */
		void unload() const { glUseProgram(0); }

	private:
		void init();
		std::string _name;
		GLuint _glName;
		ShaderPtr _vert;
		ShaderPtr _frag;
};


#endif

